package com.xyzwps.collections.list

import com.xyzwps.collections.List
import com.xyzwps.collections.Utils

import java.util.function.Supplier

import static org.junit.jupiter.api.Assertions.*

class TestList {

    static void "case - add and clear"(List<Integer> list) {
        assertTrue list.isEmpty()
        assertFalse list.isNotEmpty()

        final int MAX = 2312
        for (int i = 1; i <= MAX; i++) {
            list.add(i)
            assertEquals list.size(), i
            assertTrue list.isNotEmpty()
            assertFalse list.isEmpty()
        }

        list.clear()
        assertTrue list.isEmpty()
        assertFalse list.isNotEmpty()
    }

    static void "case - add and get"(List<Integer> list) {
        final int MAX = 3456
        for (int i = 1; i <= MAX; i++) {
            list.add(i)
            assertEquals list.size(), i
            assertTrue list.isNotEmpty()
            assertFalse list.isEmpty()
        }
        for (int i = 1; i <= MAX; i++)
            assertEquals i, list.getAt(i - 1)

        for (int i = 1; i < 10000; i++)
            assertThrows IndexOutOfBoundsException.class, () -> list.getAt(0 - i)
        for (int i = 0; i < 10000; i++)
            assertThrows IndexOutOfBoundsException.class, () -> list.getAt(list.size() + i)
    }

    static void "case - add and contains and indexOf"(List<Integer> list) {
        final int MAX = 4346
        for (int i = 1; i <= MAX; i++) list.add(i)

        for (int i = -2332; i <= MAX + 2352; i++) {
            if (i < 1) {
                assertFalse list.has(i)
                assertFalse i in list
                assertEquals list.indexOf(i), -1
            } else if (i <= MAX) {
                assertTrue list.has(i)
                assertTrue i in list
                assertEquals list.indexOf(i), i - 1
            } else {
                assertFalse list.has(i)
                assertFalse i in list
                assertEquals list.indexOf(i), -1
            }
        }
    }

    static void "case - addAll"(List<Integer> list) {
        final int MAX = 107
        for (int i = 1; i <= MAX; i++) {
            list.addAll(Utils.newArray(i, i))
            final int targetSize = ((1 + i) * i) >> 1
            assertEquals list.size(), targetSize
            assertTrue list.isNotEmpty()
            assertFalse list.isEmpty()
        }

        for (int i = 1; i <= MAX; i++) {
            final int start = (i * (i - 1)) >> 1
            for (int j = start; j < start + i; j++)
                assertEquals list.getAt(j), i
        }

        assertThrows NullPointerException.class, { list.addAll(null) }
    }

    static void "case - add and set"(List<Integer> list) {
        final int MAX = 798
        // 往列表里加一堆数
        for (int i = 1; i <= MAX; i++) {
            list.add(i)
            assertEquals list.size(), i
            assertTrue list.isNotEmpty()
            assertFalse list.isEmpty()
        }

        // 断言加成了，并修改这些数
        for (int i = 0; i < MAX; i++) {
            assertEquals list[i], i + 1
            list.putAt(i, i * 3)
            assertEquals list.size(), MAX
        }

        // 断言修改成了
        for (int i = 0; i < MAX; i++) {
            assertEquals list[i], i * 3
            assertEquals list.size(), MAX
        }

        // 指标过小
        for (int i = 1; i < 10000; i++)
            assertThrows IndexOutOfBoundsException.class, () -> list.putAt(0 - i, i)

        // 指标过大
        for (int i = 0; i < 10000; i++)
            assertThrows IndexOutOfBoundsException.class, () -> list.putAt(list.size() + i, i)
    }

    static void "case - insertAt"(List<Integer> list) {
        final integers = new Integer[877]
        final int DV = 98 // default value
        Arrays.fill(integers, DV)

        list.addAll(integers)

        // 把 list 的从第 0 个位置到第 n - 1 个位置逐个尝试插入
        for (int i = 0; i < integers.length; i++) {
            list.insertAt(i, 1)
            assertEquals list.size(), integers.length + 1
            for (int t = 0; t < list.size(); t++)
                assertEquals list[t], t == i ? 1 : DV

            list.clear()
            list.addAll(integers)
        }

        // 指标过小
        for (int i = 1; i < 10000; i++)
            assertThrows IndexOutOfBoundsException.class, () -> list.insertAt(0 - i, i)

        // 指标过大
        for (int i = 0; i < 10000; i++)
            assertThrows IndexOutOfBoundsException.class, () -> list.insertAt(list.size() + i, i)
    }

    static void "case - removeAt"(List<Integer> list) {
        final integers = new Integer[643]
        for (int i = 0; i < integers.length; i++)
            integers[i] = i + 7

        list.addAll(integers)

        // 把 list 的从第 0 个位置到第 n - 1 个位置逐个尝试删除
        for (int i = 0; i < integers.length; i++) {
            assertEquals list.removeAt(i), i + 7
            assertEquals list.size(), integers.length - 1
            for (int t = 0; t < list.size(); t++)
                assertEquals list[t], t >= i ? t + 8 : t + 7

            list.clear()
            list.addAll(integers)
        }

        // 指标过小
        for (int i = 1; i < 10000; i++)
            assertThrows IndexOutOfBoundsException.class, () -> list.removeAt(0 - i)

        // 指标过大
        for (int i = 0; i < 10000; i++)
            assertThrows IndexOutOfBoundsException.class, () -> list.removeAt(list.size() + i)
    }

    static void 'case - remove'(List<Integer> list) {
        final integers = new Integer[678]
        for (int i = 0; i < integers.length; i++)
            integers[i] = i

        list.addAll(integers)

        // 从 list 中逐个删除 0 到 n - 1
        for (int i = 0; i < integers.length; i++) {
            assertEquals list.removeFirst(i), i
            assertEquals list.size(), integers.length - 1
            for (int t = 0; t < list.size(); t++)
                assertEquals list[t], t >= i ? t + 1 : t

            list.clear()
            list.addAll(integers)
        }

        // 移除超出范围之外的元素
        for (int i = 1; i < 10000; i++)
            assertEquals list.removeFirst(0 - i), -1
        for (int i = 0; i < 10000; i++)
            assertEquals list.removeFirst(list.size() + i), -1
    }


    static void 'case - indexOf'(List<Integer> list) {
        final integers = new Integer[688]
        for (int i = 0; i < integers.length; i++)
            integers[i] = i

        list.addAll(integers)

        for (int i = 0; i < integers.length; i++) {
            assertEquals list.indexOf(i), i
            assertEquals list.size(), integers.length
        }

        for (int i = 1; i < 10000; i++)
            assertEquals list.indexOf(0 - i), -1
        for (int i = 0; i < 10000; i++)
            assertEquals list.indexOf(list.size() + i), -1
    }

    static def "case - forEach - for-in - Iterator"(Supplier<List<Integer>> supplier) {

        Supplier<List<Integer>> listGen = () -> {
            final integers = new Integer[2323]
            for (int i = 0; i < integers.length; i++)
                integers[i] = i
            def list = supplier.get()
            list.addAll(integers)
            return list
        }

        int counter = 0
        listGen.get().forEach { v ->
            assertEquals v, counter
            counter++
        }

        counter = 0
        for (def v : listGen.get()) {
            assertEquals v, counter
            counter++
        }

        counter = 0
        def itr = listGen.get().iterator()
        while (itr.hasNext()) {
            assertEquals itr.next(), counter
            counter++
        }

        // 在使用 forEach、for-in 和 Iterator 进行迭代时，不可修改列表本身

        add:
        {
            def list = listGen.get()
            assertThrows ConcurrentModificationException.class, {
                list.forEach { list.add(1) }
            }
            assertThrows ConcurrentModificationException.class, {
                for (def i : list) list.add(i)
            }
            assertThrows ConcurrentModificationException.class, {
                def itx = list.iterator()
                while (itx.hasNext()) list.add(1)
            }
        }

        set:
        {
            def list = listGen.get()
            assertThrows ConcurrentModificationException.class, {
                list.forEach { list[0] = 1 }
            }
            assertThrows ConcurrentModificationException.class, {
                for (def i : list) list[0] = 1
            }
            assertThrows ConcurrentModificationException.class, {
                def itx = list.iterator()
                while (itx.hasNext()) list[0] = 1
            }
        }

        insertAt:
        {
            def list = listGen.get()
            assertThrows ConcurrentModificationException.class, {
                list.forEach { list.insertAt(0, 1) }
            }
            assertThrows ConcurrentModificationException.class, {
                for (def i : list) list.insertAt(0, 1)
            }
            assertThrows ConcurrentModificationException.class, {
                def itx = list.iterator()
                while (itx.hasNext()) list.insertAt(0, 1)
            }
        }

        removeAt:
        {
            def list = listGen.get()
            assertThrows ConcurrentModificationException.class, {
                list.forEach { list.removeAt(0) }
            }
            assertThrows ConcurrentModificationException.class, {
                for (def i : list) list.removeAt(0)
            }
            assertThrows ConcurrentModificationException.class, {
                def itx = list.iterator()
                while (itx.hasNext()) list.removeAt(0)
            }
        }

        remove:
        {
            def list = listGen.get()
            assertThrows ConcurrentModificationException.class, {
                list.forEach { list.removeFirst(1) }
            }
            assertThrows ConcurrentModificationException.class, {
                for (def i : list) list.removeFirst(1)
            }
            assertThrows ConcurrentModificationException.class, {
                def itx = list.iterator()
                while (itx.hasNext()) list.removeFirst(1)
            }
        }

        clear:
        {
            def list1 = listGen.get()
            assertThrows ConcurrentModificationException.class, {
                list1.forEach { list1.clear() }
            }
            def list2 = listGen.get()
            assertThrows ConcurrentModificationException.class, {
                for (def i : list2) list2.clear()
            }
            def list3 = listGen.get()
            assertThrows ConcurrentModificationException.class, {
                def itx = list3.iterator()
                while (itx.hasNext()) list3.clear()
            }
        }
    }

    static void testCommon(Supplier<List<Integer>> supplier) {
        "case - add and clear" supplier.get()
        "case - add and get" supplier.get()
        "case - addAll" supplier.get()
        "case - add and contains and indexOf" supplier.get()
        "case - add and set" supplier.get()
        "case - insertAt" supplier.get()
        "case - removeAt" supplier.get()
        "case - remove" supplier.get()
        "case - indexOf" supplier.get()
        "case - forEach - for-in - Iterator" supplier
    }
}
